from datetime import datetime, timedelta
from typing import Optional, Dict, Any
import random
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import HTTPException, status, Depends
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from config import get_settings
import logging

# 密码加密上下文（默认使用bcrypt_sha256，兼容旧bcrypt哈希）
pwd_context = CryptContext(
    schemes=["bcrypt_sha256", "bcrypt"],
    default="bcrypt_sha256",
    deprecated="auto",
)

# 降低 passlib 内部 bcrypt 后端的日志级别，避免无害的版本读取警告噪音
logging.getLogger("passlib.handlers.bcrypt").setLevel(logging.ERROR)

# HTTP Bearer认证（关闭自动错误以便统一返回401）
security = HTTPBearer(auto_error=False)

# 获取配置
settings = get_settings()

def create_access_token(data: Dict[str, Any], expires_delta: Optional[timedelta] = None) -> str:
    """
    创建JWT访问令牌
    
    Args:
        data: 要编码的数据
        expires_delta: 过期时间增量
    
    Returns:
        str: JWT令牌字符串
    """
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=settings.access_token_expire_minutes)
    
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, settings.secret_key, algorithm=settings.algorithm)
    return encoded_jwt

def verify_token(token: str) -> Dict[str, Any]:
    """
    验证JWT令牌
    
    Args:
        token: JWT令牌字符串
    
    Returns:
        Dict[str, Any]: 解码后的数据
    
    Raises:
        HTTPException: 令牌无效时抛出401错误
    """
    try:
        payload = jwt.decode(token, settings.secret_key, algorithms=[settings.algorithm])
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            headers={"WWW-Authenticate": "Bearer"},
        )

def get_password_hash(password: str) -> str:
    """
    生成密码哈希
    
    Args:
        password: 明文密码
    
    Returns:
        str: 哈希后的密码
    """
    return pwd_context.hash(password)

def verify_password(plain_password: str, hashed_password: str) -> bool:
    """
    验证密码
    
    Args:
        plain_password: 明文密码
        hashed_password: 哈希密码
    
    Returns:
        bool: 密码是否匹配
    """
    try:
        return pwd_context.verify(plain_password, hashed_password)
    except Exception:
        return False

def get_current_user_id(credentials: HTTPAuthorizationCredentials = Depends(security)) -> int:
    """
    从JWT令牌中获取当前用户ID
    
    Args:
        credentials: HTTP认证凭据
    
    Returns:
        int: 用户ID
    
    Raises:
        HTTPException: 未认证或令牌无效时抛出401错误
    """
    if credentials is None or not getattr(credentials, "credentials", None):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Not authenticated",
            headers={"WWW-Authenticate": "Bearer"},
        )
    payload = verify_token(credentials.credentials)
    user_id_str = payload.get("sub")
    if user_id_str is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    try:
        user_id = int(user_id_str)
    except (ValueError, TypeError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return user_id

def get_current_user(credentials: HTTPAuthorizationCredentials = Depends(security)):
    """
    从JWT令牌中获取当前用户完整信息
    
    Args:
        credentials: HTTP认证凭据
    
    Returns:
        dict: 用户信息字典
    
    Raises:
        HTTPException: 未认证或令牌无效时抛出401错误
    """
    from sqlalchemy.orm import Session
    from database.connection import get_db
    from database.models import User
    
    if credentials is None or not getattr(credentials, "credentials", None):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="未认证",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # 获取用户ID
    payload = verify_token(credentials.credentials)
    user_id_str = payload.get("sub")
    if user_id_str is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌无效",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    try:
        user_id = int(user_id_str)
    except (ValueError, TypeError):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="令牌格式错误",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    username = payload.get("username", "")
    
    return {
        "id": user_id,
        "username": username,
        "role": "admin" if user_id == 13 else "user"
    }

def create_user_token(user_id: int, username: str) -> Dict[str, Any]:
    """
    为用户创建令牌
    
    Args:
        user_id: 用户ID
        username: 用户名
    
    Returns:
        Dict[str, Any]: 包含令牌信息的字典
    """
    access_token_expires = timedelta(minutes=settings.access_token_expire_minutes)
    access_token = create_access_token(
        data={"sub": str(user_id), "username": username},
        expires_delta=access_token_expires
    )
    
    return {
        "access_token": access_token,
        "token_type": "bearer",
        "expires_in": settings.access_token_expire_minutes * 60
    }

def validate_phone_number(phone: str) -> bool:
    """
    验证手机号格式
    
    Args:
        phone: 手机号
    
    Returns:
        bool: 手机号是否有效
    """
    import re
    pattern = r"^1[3-9]\d{9}$"
    return bool(re.match(pattern, phone))

def validate_email(email: str) -> bool:
    """
    验证邮箱格式
    
    Args:
        email: 邮箱地址
    
    Returns:
        bool: 邮箱是否有效
    """
    import re
    pattern = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
    return bool(re.match(pattern, email))

def generate_verification_code() -> str:
    """
    生成6位数字验证码
    
    Returns:
        str: 6位验证码
    """
    import random
    return str(random.randint(100000, 999999))
